package ProjectViewer.Window;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JInternalFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import ClassData.ClassData;
import ClassData.ClassDataList;
import ClassData.FieldInfo;
import ClassData.MethodInfo;

/**
 * Display the content of all class files.
 *  
 * @author Dominik Ollesz
 */
public class Window_ClassView extends JInternalFrame {

	private static final long serialVersionUID = -4176390647963924583L;

	private JTree tree;
	
	public Window_ClassView(String rootDirectory){
		super("Classes", false, false, false, true);
		setSize(new Dimension(330,700));
		
		tree = new JTree(buildTree(rootDirectory));
		getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
		getContentPane().add(new TopToolBar(),      BorderLayout.NORTH);
		getContentPane().add(new BottomToolBar(),   BorderLayout.SOUTH);
		setVisible(true);
	}

	/**
	 * Build tree representation of classes.
	 * @param rootDirectory
	 * @return Tree representation
	 */
	private DefaultMutableTreeNode buildTree(String rootDirectory) {
		
		// traverse files in root directory 
		// and create class data
		ClassDataList list = new ClassDataList();
		loadClasses(new File(rootDirectory), list);
		list.parseDataList();

		DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootDirectory);
		for (ClassData classData : list) {
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(classData.getClassName());
			addFieldInfo(classData, node);
			addMethodInfo(classData, node);
			root.add(node);
		}
		
		return root;
	}
	
	/**
	 * Append field informations to given node.
	 * @param classData ClassData with field informations.
	 * @param node
	 */
	private void addFieldInfo(ClassData classData, DefaultMutableTreeNode node) {
		DefaultMutableTreeNode fieldNode = new DefaultMutableTreeNode("Fields - " + classData.getFieldsCount());
		for (FieldInfo fieldInfo : classData.getFields()) {
			DefaultMutableTreeNode field = new DefaultMutableTreeNode(fieldInfo.getFieldName());
			fieldNode.add(field);
			field.add(new DefaultMutableTreeNode("Data size: "        + fieldInfo.getDataSize()));
			field.add(new DefaultMutableTreeNode("Descriptor index: " + fieldInfo.getDescriptorIndex()));
			field.add(new DefaultMutableTreeNode("Field type: "       + fieldInfo.getFieldType()));
			field.add(new DefaultMutableTreeNode("Flags: "            + fieldInfo.getFlags() + " " + fieldInfo.getFlagsAsString()));
			field.add(new DefaultMutableTreeNode("Name Index: "       + fieldInfo.getNameIndex()));
		}
		node.add(fieldNode);
	}
	
	/**
	 * Append method informations to given node.
	 * @param classData ClassData with method informations.
	 * @param node 
	 */
	private void addMethodInfo(ClassData classData, DefaultMutableTreeNode node) {
		DefaultMutableTreeNode methodNode = new DefaultMutableTreeNode("Methods - " + classData.getMethodsCount());
		for (MethodInfo methodinfo : classData.getMethods()) {
			DefaultMutableTreeNode method = new DefaultMutableTreeNode(methodinfo.getMethodName());
			methodNode.add(method);
			method.add(new DefaultMutableTreeNode("Code size: "           + methodinfo.getCodeSize()));
			method.add(new DefaultMutableTreeNode("Descriptor index: "    + methodinfo.getDescriptorIndex()));
			method.add(new DefaultMutableTreeNode("Flags: "               + methodinfo.getFlags() + " " + methodinfo.getFlagsAsString()));
			method.add(new DefaultMutableTreeNode("Max locals : "         + methodinfo.getMaxLocals()));
			method.add(new DefaultMutableTreeNode("Max stack : "          + methodinfo.getMaxStack()));
			method.add(new DefaultMutableTreeNode("Name index: "          + methodinfo.getNameIndex()));
			method.add(new DefaultMutableTreeNode("Parameter Ccount: " + methodinfo.getParameterCount()));
			method.add(new DefaultMutableTreeNode("Parameter: "           + methodinfo.getParametersAsString()));
		}
		node.add(methodNode);
	}
	
	/**
	 * 
	 * @param rootDirectory
	 * @param list
	 */
	private void loadClasses(File rootDirectory, ClassDataList list) {
		if (rootDirectory.isDirectory()) {			
			for (File file : rootDirectory.listFiles()) {
				if (file.isDirectory()) {
					loadClasses(file, list);
				} else if (file.getName().endsWith(".class")) {
					list.add(new ClassData(file));
				}
			}
		}		
	}
	
	/**
	 * 
	 * @param rootDirectory
	 */
	public void changeDirectory(String rootDirectory) {
		tree.setModel(new DefaultTreeModel(buildTree(rootDirectory)));
		tree.repaint();
		repaint();
	}

	class TopToolBar extends JPanel {
		
		private static final long serialVersionUID = -3437015126789191222L;
		
		private final String[][] buttonlabel = 
			{{"change Directory", "refresh"},
			 {"Verzeichnis wechseln", "aktualisieren"}};
		
		public TopToolBar() {
			super();
			
			// Button 1
			JButton button = new JButton(buttonlabel[0][0]);
			button.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					changeDirectory("D:/jvm_workspace/Test_Exception/");
				}
			});
			add(button);
			
			// Button 2
			button = new JButton(buttonlabel[0][1]);
			button.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.out.println(buttonlabel[0][1]+ ": not implemented yet");
				}
			});
			add(button);
		}
		
	}
	
	class BottomToolBar extends JPanel {

		private static final long serialVersionUID = 5470803130352880526L;

		private final String[][] buttonlabels = {
			{"A", "B", "C", "D"},
			{"A", "B", "C", "D"}};
		
		public BottomToolBar() {
			super();
			
			// Button 1
			JButton b = new JButton(buttonlabels[0][0]);
			b.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.out.println(buttonlabels[0][0]+ ": not implemented yet");
				}
			});
			add(b);
			
			// Button 2
			b = new JButton(buttonlabels[0][1]);
			b.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.out.println(buttonlabels[0][1]+ ": not implemented yet");
				}
			});
			add(b);
			
			// Button 3
			b = new JButton(buttonlabels[0][2]);
			b.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.out.println(buttonlabels[0][2]+ ": not implemented yet");
				}
			});
			add(b);
			
			// Button 4
			b = new JButton(buttonlabels[0][3]);
			b.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.out.println(buttonlabels[0][3]+ ": not implemented yet");
				}
			});
			add(b);
		}
	}
	
}